import { Cookie, RequestEventBase, RequestEventCommon } from '@builder.io/qwik-city';
import { createJwt, verifyJwt, decodeJwt } from './jwt';
import { db } from './db';
import { type UserAccount } from '@prisma/client';
import _ from 'lodash';
import logger from './logger';
import { getServerEnv } from './env';
import { yesorno } from '~/common/yesorno';
import { Result } from '~/common/types';
import { userAccountService } from './service/user-account-service';

const TOKEN_COOKIE_NAME = 'p_token';
const COOKIE_SECURE = yesorno(getServerEnv('COOKIE_SECURE'));

type AuthCheckOK = { userId: bigint; sessionId: string; userAccount: UserAccount };

export async function checkAuth(req: RequestEventBase): Promise<Result<AuthCheckOK, string>> {
  const cookieValue = req.cookie.get(TOKEN_COOKIE_NAME);
  if (!cookieValue) {
    return { ok: false, error: '尚未登录' };
  }

  const jwt = cookieValue.value;

  const result = await verifyJwt(jwt);
  if (!result.ok) {
    return { ok: false, error: '登录已过期' };
  }

  const userAccount = await userAccountService.findByUserId(db, result.userId);
  if (!userAccount) {
    return { ok: false, error: '用户不存在' };
  }

  if (userAccount.disabled) {
    return { ok: false, error: '你已被禁用' };
  }
  if (userAccount.locked) {
    return { ok: false, error: '你已被锁定' };
  }

  // TODO: 检查 session 状态

  return { ok: true, data: { userId: result.userId, sessionId: result.sessionId, userAccount } };
}

export async function shouldAuth(ev: RequestEventCommon) {
  const auth = await checkAuth(ev);
  if (!auth.ok) {
    throw ev.redirect(307, '/login');
  }

  ev.sharedMap.set('userId', auth.data.userId);
  ev.sharedMap.set('sessionId', auth.data.sessionId);
  ev.sharedMap.set('userAccount', auth.data.userAccount);
}

export function getUserId(ev: RequestEventCommon): bigint {
  const userId = ev.sharedMap.get('userId');
  if (userId == null) {
    throw ev.redirect(307, '/login');
  }
  return userId as bigint;
}

export function getUserAccount(ev: RequestEventCommon): UserAccount {
  const account = ev.sharedMap.get('userAccount');
  if (account == null) {
    throw ev.redirect(307, '/login');
  }
  return account as UserAccount;
}

export async function authenticate(cookie: Cookie, userId: bigint) {
  const { jwt, maxAge } = await createJwt(userId);
  cookie.set(TOKEN_COOKIE_NAME, jwt, { maxAge: [maxAge, 'hours'], httpOnly: true, secure: COOKIE_SECURE, path: '/' });
}

export async function logout(cookie: Cookie) {
  const cookieValue = cookie.get(TOKEN_COOKIE_NAME);
  if (!cookieValue) {
    return;
  }
  logger.info('[logout]', await decodeJwt(cookieValue.value));
  cookie.set(TOKEN_COOKIE_NAME, '', { maxAge: [0, 'hours'], httpOnly: true, secure: COOKIE_SECURE, path: '/' });
}
